package api

import (
    "errors"
    "fmt"
    "github.com/tidwall/gjson"
    "github.com/valyala/fasthttp"
    "hitme/go-api/modules/utils"
    "net/http"
    "net/url"
    "strings"
    "time"
)

type RequestForm struct {
    Uri      string
    Params   interface{}
    Header   url.Values
    RespBody string
    Resp     interface{}
}

type client struct{}

type IClient interface {
    Post(dto *RequestForm) error
    Get(dto *RequestForm) error
    Put(dto *RequestForm) error
}

var Client IClient = new(client)

func (*client) Post(dto *RequestForm) error {
    req := fasthttp.AcquireRequest()
    resp := fasthttp.AcquireResponse()
    defer func() {
        fasthttp.ReleaseResponse(resp)
        fasthttp.ReleaseRequest(req)
    }()

    req.SetBody(utils.JsonMarshalByte(dto.Params))
    req.SetRequestURI(dto.Uri)
    req.Header.SetContentType("application/json")
    req.Header.SetMethod(http.MethodPost)

    if dto.Header != nil {
        for k, v := range dto.Header {
            req.Header.Set(k, strings.Join(v, ","))
        }
    }

    if err := fasthttp.DoTimeout(req, resp, 30*time.Second); err != nil {
        return err
    }

    dto.RespBody = string(resp.Body())
    fmt.Println(dto.RespBody)

    if resp.StatusCode() >= fasthttp.StatusBadRequest {
        return errors.New(gjson.Get(dto.RespBody, "message").String())
    }

    if dto.Resp != nil {
        utils.JsonUnmarshal(dto.RespBody, dto.Resp)
    }

    return nil
}

func (*client) Get(dto *RequestForm) error {
    req := fasthttp.AcquireRequest()
    resp := fasthttp.AcquireResponse()
    defer func() {
        fasthttp.ReleaseResponse(resp)
        fasthttp.ReleaseRequest(req)
    }()

    req.SetRequestURI(dto.Uri)
    req.Header.SetMethod(http.MethodGet)

    if dto.Header != nil {
        for k, v := range dto.Header {
            req.Header.Set(k, strings.Join(v, ","))
        }
    }

    if err := fasthttp.DoTimeout(req, resp, 30*time.Second); err != nil {
        return err
    }

    dto.RespBody = string(resp.Body())

    if resp.StatusCode() >= fasthttp.StatusBadRequest {
        return errors.New(gjson.Get(dto.RespBody, "message").String())
    }

    if dto.Resp != nil {
        utils.JsonUnmarshal(dto.RespBody, dto.Resp)
    }

    return nil
}

func (*client) Put(dto *RequestForm) error {
    req := fasthttp.AcquireRequest()
    resp := fasthttp.AcquireResponse()
    defer func() {
        fasthttp.ReleaseResponse(resp)
        fasthttp.ReleaseRequest(req)
    }()

    req.SetBody(utils.JsonMarshalByte(dto.Params))
    req.SetRequestURI(dto.Uri)
    req.Header.SetContentType("application/json")
    req.Header.SetMethod(http.MethodPut)

    if dto.Header != nil {
        for k, v := range dto.Header {
            req.Header.Set(k, strings.Join(v, ","))
        }
    }

    if err := fasthttp.DoTimeout(req, resp, 30*time.Second); err != nil {
        return err
    }

    dto.RespBody = string(resp.Body())

    if resp.StatusCode() >= fasthttp.StatusBadRequest {
        return errors.New(gjson.Get(dto.RespBody, "message").String())
    }

    if dto.Resp != nil {
        utils.JsonUnmarshal(dto.RespBody, dto.Resp)
    }

    return nil
}